﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Quartz;
using Quartz.Impl;
using System.Reflection;

namespace Luka;

/// <summary>
/// Quartz
/// </summary>
[NotScanned]
public static class QuartzSetup
{
    /// <summary>
    /// 添加特性定时任务
    /// </summary>
    /// <returns></returns>
    public static WebApplicationBuilder AddAttributeQuartz(this WebApplicationBuilder builder)
    {
        builder.Services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
        var assembly = InternalApp.TypeList.Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToList();
        assembly.ForEach(type =>
        {
            foreach (var methodInfo in type.GetMethods())
            {
                if (methodInfo.HasAttribute<QuartzTaskAttribute>())
                {
                    builder.Services.TryAddTransient(type);
                    return;
                }
            }
        });
        return builder;
    }

    /// <summary>
    /// 启用特性定时任务
    /// </summary>
    /// <returns></returns>
    public static IApplicationBuilder StartAttributeQuartz(this IApplicationBuilder app)
    {
        var provider = app.ApplicationServices.CreateScope().ServiceProvider;
        ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
        IScheduler ischeduler = schedulerFactory.GetScheduler().Result;
        var assembly = InternalApp.TypeList.Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToList();
        var quartzJobs = new Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>>();
        assembly.ForEach(type =>
        {
            foreach (var methodInfo in type.GetMethods())
            {
                var taskAttribute = methodInfo.GetAttribute<QuartzTaskAttribute>();
                if (taskAttribute != null)
                {
                    var (job, trigger) = CreateActionQuartz(methodInfo, taskAttribute, type, provider);
                    quartzJobs.Add(job, new List<ITrigger>() { trigger });
                }
            }
        });
        ischeduler.ScheduleJobs(quartzJobs, true);
        ischeduler.Start();
        return app;
    }

    /// <summary>
    /// 生成定时任务
    /// </summary>
    /// <returns></returns>
    private static (IJobDetail job, ITrigger trigger) CreateActionQuartz(MethodInfo method, QuartzTaskAttribute attribute, Type type, IServiceProvider provider)
    {
        IDictionary<string, object> dic = new Dictionary<string, object>()
        {
            { "obj", new QuartzData
                {
                    ServiceProvider = provider,
                    ControllerType = type,
                    Method = method,
                    Attribute = attribute
                }
            }
        };
        IJobDetail job = JobBuilder.Create<QuartzJob>().WithIdentity(method.Name, method.DeclaringType.Name).SetJobData(new JobDataMap(dic)).Build();
        ITrigger trigger;
        var builder = TriggerBuilder.Create();
        //判断是否使用Cron表达式
        if (!string.IsNullOrEmpty(attribute.CronExpression))
        {
            builder.WithCronSchedule(attribute.CronExpression);
        }
        else
        {
            builder.WithSimpleSchedule(x =>
            {
                if (attribute.IsRepeatForever)
                {
                    x.RepeatForever().WithIntervalInSeconds(attribute.IntervalInSeconds);
                }
                else
                {
                    x.WithRepeatCount(attribute.RepeatCount - 1).WithIntervalInSeconds(attribute.IntervalInSeconds);
                }
            });
        }
        trigger = builder.Build();
        return (job, trigger);
    }
}